class_name GameplayState
extends Node
## Gameplay State
## Version: 0.1.0

##
var transitions: Array[GameplayStateTransition] = []


func get_state(state_path: String) -> GameplayState:
	return self if state_path.is_empty() else null
	

func get_current_state() -> GameplayState:
	return self


func get_current_state_name() -> String:
	return name


func dispatch_event(event_name: String) -> void:
	for transition: EventStateTransition in transitions:
		# dispatch_event 只处理 EventStateTransition
		if transition and\
		   transition.event_name == event_name and\
		   change_state(transition.try_transition(), transition.on_transit):
			return

	var state_machine = get_parent() as GameplayStateMachine
	if state_machine:
		state_machine.dispatch_event(event_name)


func change_state(target_state_name: String, on_transit: Callable) -> bool:
	var state_machine = get_parent() as GameplayStateMachine
	if not state_machine:
		return false

	assert(state_machine, "State machine should not be null!")
	assert(state_machine.states.has(target_state_name), "Target state do not have the same state machine of this state!")
	assert(target_state_name != "AnyState", "Can not change to AnyState!")

	if target_state_name == state_machine.current_state_name:
		return false

	state_machine.states[state_machine.current_state_name].on_exit()
	state_machine.current_state_name = target_state_name
	on_transit.call()
	state_machine.states[target_state_name].on_enter()

	return true


func on_setup() -> void:
	_on_setup()


func on_enter() -> void:
	_on_enter()

	if name == "GhostState":
		assert(try_all_transitions() or get_parent().states["AnyState"].try_all_transitions(), "GhostState must be exited!")
		return


func try_all_transitions() -> bool:
	for transition: GameplayStateTransition in transitions:
		# EventStateTransition 只在 dispatch_event 中进行转移，不在此处处理
		if transition is not EventStateTransition and\
		   transition.try_condition() and\
		   change_state(transition.try_transition(), transition.on_transit):
			return true

	return false


func on_update(delta: float) -> void:
	if not try_all_transitions():
		_on_update(delta)


func on_exit() -> void:
	_on_exit()


#region Need to override
func _on_setup() -> void:
	pass


func _on_enter() -> void:
	pass


func _on_update(_delta: float) -> void:
	pass


func _on_exit() -> void:
	pass
#endregion
